home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
mdbg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
9KB
|
384 lines
/*
* $Id: mdbg.c,v 0.91 1994/02/20 02:17:36 zhao Exp $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Wrapper for malloc and its cousins.
* All routines work by calling true malloc with some extra space
* for signatures, where is is called and other info. When request
* to free, realloc etc is called, these info is examined to make
* sure the memory handed over is ok. In addition, memory usage
* statistics can be obtained anywhere by calling mem_stat which
* will print out all malloced memory that are not yet freed and
* functions and line no. where malloc is called.
*
* WARNING: Neither efficient nor portable. It assumes 4 bytes
* alignment.
*
*/
#ifdef M_DBG
#if !defined(lint) && defined(F_ID)
char *id_dbgm = "$Id: mdbg.c,v 0.91 1994/02/20 02:17:36 zhao Exp $";
#endif
#define M_DBG_OWNER /* dmalloc.h notices this and refrain from
* replacing malloc with dbg_malloc */
#include <stdio.h>
#include <string.h>
#include "ulib.h"
#include "dmalloc.h"
typedef long STYPE; /* must be at least 4bytes long */
#define MAX_FL 15
#define MAX_REC 500 /* max malloc etc record to keep */
#define OK_MEM 0xcfdcfaef /* good memory head signature */
#define ED_MEM 0xdfefafdf /* good memory end signature */
#define FR_MEM 0xeffbffcf /* freed block */
#define TOTAL_OFF 3*sizeof(STYPE) /* user memory starts 3 ints off */
static struct
{
void *ptr; /* pointer returned by malloc etc */
char where[MAX_FL + 1]; /* functions that called malloc */
int line; /* line number in function */
}
m_rec[MAX_REC];
/*
* True free from malloc.h or stdlib.h if no debug is used, Tfree will be a
* macros that degenerates into free
*/
void
Tfree(void *p)
{
free(p);
}
/* how to handle error messages. */
static int mem_warn = 1;
void
set_mem_warn(int y)
{
mem_warn = y;
}
/*
* Even if STYPE is 4bytes long, can't simply do a *p= s because *p
* might not be properly aligned. Remember, we are dealing with memory
* handed over by users.
*/
static void
set_4bytes(void *p, STYPE s)
{
register unsigned char *pp = p;
*pp++ = (s & 0xff);
*pp++ = ((s >> 8) & 0xff);
*pp++ = ((s >> 16) & 0xff);
*pp = ((s >> 24) & 0xff);
}
/* peek 4 bytes */
static void
get_4bytes(void *p, STYPE * s)
{
register unsigned char *pp = p;
register STYPE a, b, c, d;
a = *pp++;
b = *pp++;
c = *pp++;
d = *pp;
*s = (STYPE) a | (b << 8) | (c << 16) | (d << 24);
}
/* error output routine obeying mem_warn settings */
static void
mprintf(const char *fi, int line, const char *func, const char *s2)
{
if (mem_warn <= 0)
{ /* text only */
M_msg(ML_ERR, fi, line) (func, s2);
}
else
{
GM_msg(0, fi, line) (func, s2);
}
}
static int
find_index(const char *f, int line, const char *fun)
{
register int i;
static int warned;
for (i = 0; i < MAX_REC; i++)
if (!m_rec[i].ptr)
return i;
if (warned < 2)
{
mprintf(f, line, fun, "m_dbg record out of bounds");
warned++;
}
return -1;
}
/* insert signature, size and other info into malloc'ed mem */
static void
set_marker(void *p, STYPE sig, STYPE ind, STYPE size, STYPE esig)
{
register unsigned char *pp = p;
set_4bytes(pp, sig);
pp += sizeof(STYPE);
set_4bytes(pp, ind);
pp += sizeof(STYPE);
set_4bytes(pp, size - TOTAL_OFF);
pp += sizeof(STYPE);
pp = (unsigned char *) p + size;
set_4bytes(pp, esig);
}
/* get signature etc from the pointer in request to free, realloc etc*/
static void
get_marker(void *p, STYPE * sig, STYPE * ind,
STYPE * size, STYPE * esig)
{
register unsigned char *pp = p;
get_4bytes(pp, sig);
if (*sig != OK_MEM)
return;
pp += sizeof(STYPE);
get_4bytes(pp, ind);
if (*ind < 0 || *ind > MAX_REC - 1)
return;
pp += sizeof(STYPE);
get_4bytes(pp, size);
if (*size < 0)
return;
pp += sizeof(STYPE);
pp = (unsigned char *) p + *size + TOTAL_OFF;
get_4bytes(pp, esig);
if (*esig != ED_MEM)
return;
}
static int totalgets, totalfree;
static int
check_sig(void *p, const char *f, int line, const char *func)
{
STYPE sig = -1, sz = -1, ind = -1, esig = -1;
get_marker(p, &sig, &ind, &sz, &esig);
if (sig == FR_MEM)
{
mprintf(f, line, func, "referencing a freed block");
return -1;
}
if (sig != OK_MEM)
{
mprintf(f, line, func, "mem not malloced or is corrupted");
return -1;
}
if (ind < 0 || ind > MAX_REC - 1)
{
mprintf(f, line, func, "corrupted mem(index)");
return -1;
}
if (esig != ED_MEM)
{
mprintf(f, line, func, "malloc mem overrun at end");
return -1;
}
return ind;
}
/*
* the func is where the dyn. alloc started, possibly appened with other
* routines that called malloc (cf. strdup)
*/
void *
dbg_malloc(size_t size, const char *func, int line)
{
register void *p;
register STYPE ind;
size += TOTAL_OFF;
if (!(p = malloc(size + sizeof(STYPE))))
{
mprintf(func, line, "d_malloc", "malloc failed");
return 0;
}
totalgets++;
if ((ind = find_index(func, line, "d_malloc")) < 0)
return p;
set_marker(p, OK_MEM, ind, size, ED_MEM);
m_rec[ind].ptr = p;
m_rec[ind].where[MAX_FL] = '\0';
strncpy(m_rec[ind].where, func, MAX_FL);
m_rec[ind].line = line;
p = (char *) p + TOTAL_OFF;
return p;
}
void *
dbg_calloc(size_t nelem, size_t esize, const char *f, int line)
{
register void *p;
register size_t size = (nelem * esize);
if (!(p = dbg_malloc(size, f, line)))
return 0;
memset(p, 0, size);
return p;
}
void *
dbg_realloc(void *p, size_t nsize, const char *f, int line)
{
register STYPE ind;
register char *pc;
if (!p)
{
mprintf(f, line, "d_realloc", "NullPtr passed to realloc");
return 0;
}
pc = (char *) p - TOTAL_OFF;
if ((ind = check_sig(pc, f, line, "d_realloc")) < 0)
return 0;
nsize += TOTAL_OFF;
if (!(pc = realloc(pc, nsize + sizeof(STYPE))))
{
mprintf(f, line, "d_realloc", "realloc failed");
return 0;
}
set_marker(pc, OK_MEM, ind, nsize, ED_MEM);
m_rec[ind].ptr = pc;
pc += TOTAL_OFF;
return pc;
}
void
dbg_free(void *p, const char *f, int line)
{
char *a;
STYPE ind;
if (!p)
{
mprintf(f, line, "d_free", "NullPtr passed to free");
return;
}
a = (char *) p - TOTAL_OFF;
if ((ind = check_sig(a, f, line, "d_free")) < 0)
return;
set_4bytes(a, FR_MEM);
totalfree++;
m_rec[ind].ptr = 0;
free(a);
}
/* replace strdup from string.h */
char *
dbg_strdup(const char *s, const char *func, int line)
{
static char local[101];
char *p;
local[0] = '\0';
if (func)
{
strncat(local, func, 100);
local[100] = '\0';
}
strncat(local, "_strdup", 100);
p = dbg_malloc(strlen(s) + 1, local, line);
return p ? strcpy(p, s) : p;
}
/* print out memoery usage statistics */
void
mem_stat(void)
{
int i, diff, line;
STYPE sig, size, ind, esig;
void *p;
char *func;
double total = 0;
/*
* if mem is corrupt, we do not want to activate tc_gmsg, there could be
* zillions of messages!
*/
set_mem_warn(-1);
fprintf(stderr, "\nThere are %d malloc and %d free, unfreed are\n",
totalgets, totalfree);
diff = totalgets - totalfree;
for (i = 0; i < MAX_REC; i++)
{
if ((p = m_rec[i].ptr))
{
func = m_rec[i].where;
line = m_rec[i].line;
(void) check_sig(p, "mem_stat record no.", i, "memstat");
get_marker(p, &sig, &ind, &size, &esig);
total += size;
if (ind < 0 || ind > MAX_REC - 1)
mprintf("memstat:", i, "", "bad mem block");
else
fprintf(stderr,
"%20s line %-d:\t size %-9ld index(%d)=%ld\n",
func, line, size, i, ind);
diff--;
}
}
if (diff)
fprintf(stderr, "things are not quite right in mem_stat\n");
fprintf(stderr, " Total unfreeed: %.0f bytes\n", total);
}
#else /* !M_DBG no_op for mem_warn */
#include "dmalloc.h" /* still wants to have prototypes */
/* ARGSUSED */
void
set_mem_warn(int y)
{
return;
}
void
mem_stat(void)
{
return;
}
#endif